/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2009, Around(J2)ME				                                 **
 **   All rights reserved.                                                   **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the New BSD License which accompanies this    			 **
 **   distribution.											                 **
 **   A copy is found in the textfile LICENSE.txt							 **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Main developers:                                                       **
 **     Juri Strumpflohner		http://blog.js-development.com	             **
 **		Matthias Braunhofer		http://matthias.jimdo.com                    **
 **                                                                          **
 **  **********************************************************************  */

package org.aroundme.unittests;

import java.util.ArrayList;
import java.util.List;

import org.aroundme.controller.ApplicationController;
import org.aroundme.model.Category;
import org.aroundme.model.CategoryName;
import org.aroundme.model.Comment;
import org.aroundme.model.DateManager;
import org.aroundme.model.Location;
import org.aroundme.model.Place;
import org.aroundme.model.XMLRequestParser;
import org.aroundme.persistency.LocationManager;
import org.aroundme.unitTools.TestFixture;
import org.aroundme.unitTools.UniqueIdGenerator;
import org.aroundme.utility.Constants;
import org.aroundme.utility.HibernateUtil;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.mock.web.MockHttpServletResponse;

@SuppressWarnings("unchecked")
public class ApplicationControllerTest extends TestFixture {
	private ApplicationController controller;
	private XMLRequestParser handler;
	private LocationManager manager;
	private MockHttpServletResponse mockResponse;
	
	protected void setUp() throws Exception {
		super.setUp();
		handler = (XMLRequestParser)springFactory.getBean(XMLRequestParser.class.getSimpleName());
		controller = (ApplicationController) springFactory.getBean(ApplicationController.class.getSimpleName());
		manager = (LocationManager) springFactory.getBean(LocationManager.class.getSimpleName());
		mockResponse = new MockHttpServletResponse();
	}

	protected void tearDown() throws Exception {
		super.tearDown();
		handler = null;
		controller = null;
		manager = null;
		mockResponse = null;
	}

	/**
	 * Checks if places inside an XML string are successfully parsed out and stored into the DB
	 * @throws Exception
	 */
	public void testStoreRequest() throws Exception {
		MockHttpServletResponse mockResponse = new MockHttpServletResponse();
		xmlTestUtils.saveDummyUsersToDB();
		
		String xmlString = xmlTestUtils.createXMLCommitString(Constants.COMMIT_PLACE, "fixed", new String[]{CategoryName.HOTELS.toString(), CategoryName.BARS.toString()});
		handler.loadDocumentModel(xmlString);
		controller.setResponse(mockResponse);
		controller.storeRequest();

		//retrieve stored places
		Session s = HibernateUtil.getSessionFactory().getCurrentSession();
		Place place1 = null;
		Place place2 = null;
		Place place3 = null;
		s.beginTransaction();
		try{
			place1 = (Place) s.createQuery("from Place where name=?").setString(0, xmlTestUtils.getDummyPlaces().get(0).getName()).uniqueResult();
			place2 = (Place) s.createQuery("from Place where name=?").setString(0, xmlTestUtils.getDummyPlaces().get(1).getName()).uniqueResult();
			place3 = (Place) s.createQuery("from Place where name=?").setString(0, xmlTestUtils.getDummyPlaces().get(2).getName()).uniqueResult();
			s.getTransaction().commit();
		}catch (HibernateException e){
			s.getTransaction().rollback();
			throw e;
		}
		assertNotNull(place1);
		assertNotNull(place2);
		assertNotNull(place3);
		
		assertEquals("Name", xmlTestUtils.getDummyPlaces().get(0).getName(), place1.getName());
		assertEquals("Name", xmlTestUtils.getDummyPlaces().get(1).getName(), place2.getName());
		assertEquals("Name", xmlTestUtils.getDummyPlaces().get(2).getName(), place3.getName());
		assertEquals("Address", xmlTestUtils.getDummyPlaces().get(0).getAddress(), place1.getAddress());
		assertEquals("Address", xmlTestUtils.getDummyPlaces().get(1).getAddress(), place2.getAddress());
		assertEquals("Address", xmlTestUtils.getDummyPlaces().get(2).getAddress(), place3.getAddress());
		assertEquals("user", xmlTestUtils.getDummyPlaces().get(0).getUser().getLoginName(), place1.getUser().getLoginName());
		assertEquals("user", xmlTestUtils.getDummyPlaces().get(1).getUser().getLoginName(), place2.getUser().getLoginName());
		assertEquals("user", xmlTestUtils.getDummyPlaces().get(2).getUser().getLoginName(), place3.getUser().getLoginName());
	}
	
	/**
	 * Tests when a store-request is sent, but the containing
	 * place shouldn't be created, but its content should be updated
	 * @throws Exception 
	 *
	 */
	public void testStoreRequestEdit() throws Exception{
		xmlTestUtils.saveDummyUsersToDB();
		xmlTestUtils.saveDummyPlacesToDB(); //this will cause an edit reaction, since the places will be already in the DB when the request is handled
		
		//edit a place-title to see if it works
		xmlTestUtils.getDummyPlaces().get(1).setAddress("my test address edited!");
		
		String xmlString = xmlTestUtils.createXMLCommitString(Constants.COMMIT_PLACE, "fixed", new String[]{CategoryName.HOTELS.toString(), CategoryName.BARS.toString()});
		handler.loadDocumentModel(xmlString);
		controller.setResponse(mockResponse);
		controller.storeRequest();
		
		//retrieve from DB to see if has been edited
		Place retrieved = null;
		Session s = HibernateUtil.getSessionFactory().getCurrentSession();
		s.beginTransaction();
		try{
			retrieved = (Place) s.createQuery("from Place where id=?").setInteger(0, xmlTestUtils.getDummyPlaces().get(1).getId()).uniqueResult();
			s.getTransaction().commit();
		}catch (HibernateException e){
			s.getTransaction().rollback();
			e.printStackTrace();
			fail(e.getMessage());
		}
		
		assertNotNull(retrieved);
		assertEquals("id should be equal", xmlTestUtils.getDummyPlaces().get(1).getId(), retrieved.getId());
		assertEquals("address should be modified", xmlTestUtils.getDummyPlaces().get(1).getAddress(), retrieved.getAddress());
	}
	
	/**
	 * Stores fake-places to the DB and then creates a fake XML request and sends it to the server
	 * Checks if the previously stored places are successfully returned
	 * @throws Exception
	 */
	public void testRetrieveRequest() throws Exception{
		xmlTestUtils.saveDummyUsersToDB();
		
		controller.setResponse(mockResponse);
		
		Location loc = new Location();
		loc.setCellid("" + new UniqueIdGenerator().getUniqueId());
		loc.setLat("somelat");
		loc.setLon("someLong");
		ArrayList<Place> places = xmlTestUtils.getDummyPlaces();
		for (Place place : places) {
			loc.addPlace(place);
		}
		
		manager.saveLocation(loc);
		
		//create a fake xml retrieve request for places
		String xmlRequestString = xmlTestUtils.createXMLRetrieveString(Constants.RETRIEVE_PLACE, Constants.PARAM_RETRIEVE_ALL, null, null, 0, 9999999);
		handler.loadDocumentModel(xmlRequestString);
		
		controller.retrieveRequest();
		
		//retrieve response
		String responseString = mockResponse.getContentAsString();
		
		assertNotNull(responseString);
		for (Place place : places) {
			assertTrue("Id of place", responseString.contains("<id>" + place.getId() + "</id>"));
			assertTrue("Name of place", responseString.contains("<name>" + place.getName() + "</name>"));
			assertTrue("Address of place", responseString.contains("<address>" + place.getAddress() + "</address>"));
			assertTrue("User of place", responseString.contains("<user>" + place.getUser().getLoginName() + "</user>"));
		}
	}
	
	public void testDeleteRequest() throws Exception{
		xmlTestUtils.saveDummyUsersToDB();
		xmlTestUtils.saveDummyPlacesToDB();
		
		controller.setResponse(mockResponse);
		
		Place toDelete = xmlTestUtils.getDummyPlaces().get(2);
		//add some Categories
		Category bankCategory = new Category();
		bankCategory.setName(CategoryName.BANKS.toString());
		toDelete.getCategories().add(bankCategory);
		
		String xmlDeleteString = xmlTestUtils.createXMLDeleteString(toDelete);
		handler.loadDocumentModel(xmlDeleteString);
		
		controller.deleteRequest();
		
		//shouldn't be in the DB any more
//		check if really deleted
		Place retrievedPlace = null;
		Session s = HibernateUtil.getSessionFactory().getCurrentSession();
		s.beginTransaction();
		try{
			retrievedPlace = (Place) s.createQuery("from Place where id=?").setInteger(0, toDelete.getId()).uniqueResult();
			s.getTransaction().commit();
		}catch(HibernateException e){
			s.getTransaction().rollback();
			e.printStackTrace();
			fail(e.getMessage());
		}
		
		assertNull(retrievedPlace);
	}
	
	public void testStorePlaceComment() throws Exception{
		xmlTestUtils.saveDummyUsersToDB();
		xmlTestUtils.saveDummyPlacesToDB();
		Comment mycomment = new Comment();
		mycomment.setComment("Hello, my comment" + new UniqueIdGenerator().getUniqueId());
		mycomment.setUser(xmlTestUtils.getDummyUsers().get(1));
		Place p = new Place();
		p.setId(xmlTestUtils.getDummyPlaces().get(0).getId());
		mycomment.setPlace(p);
		
		String xmlCommentString = xmlTestUtils.createXMLCommitStringComment(Constants.COMMIT_PLACE_COMMENT, mycomment);
		handler.loadDocumentModel(xmlCommentString);
		controller.setResponse(mockResponse);
		
		controller.storePlaceComment();
		
		//retrieve place and check if comment is attached to it
		Place retrievedPlace = null;
		Session s = HibernateUtil.getSessionFactory().getCurrentSession();
		s.beginTransaction();
		try{
			retrievedPlace = (Place) s.createQuery("from Place where id=?").setInteger(0, p.getId()).uniqueResult();
			s.getTransaction().commit();
		}catch(HibernateException e){
			s.getTransaction().rollback();
			e.printStackTrace();
			fail(e.getMessage());
		}
		
		assertNotNull(retrievedPlace);
		
		boolean found = false;
		List comments = new ArrayList();
		comments.addAll(retrievedPlace.getComments());
		for (Object object : comments) {
			Comment tmp = (Comment) object;
			if(tmp.getComment().equals(mycomment.getComment())){
				found = true;
			}
		}
		
		assertTrue(found);
	}

}
